// Includes
#include "Vector.h"

#include <cmath>			// C math library
#include <exception>		// Exception header

// Vector2 default constructor
Vector2::Vector2()
	: X(m_data[0]), Y(m_data[1])
{

	// Set components
	for (int i = 0; i < 2; i++)
		m_data[i] = 0.0f;
}

// Vector2 constructor setting all components to the same value
Vector2::Vector2(float compValue)
	: X(m_data[0]), Y(m_data[1])
{
	// Set components
	for (int i = 0; i < 2; i++)
		m_data[i] = compValue;
}

// Vector2 constructor with parameters
Vector2::Vector2(float x, float y)
	: X(m_data[0]), Y(m_data[1])
{
	X = x;
	Y = y;
}

// Sets components
void Vector2::Set(float x, float y)
{
	X = x;
	Y = y;
}

// Copies components from another vector
void Vector2::Set(const Vector2& vector)
{
	for (int i = 0; i < 2; i++)
		m_data[i] = vector.m_data[i];
}

// Sets all vector components to zero
void Vector2::Zero()
{
	for (int i = 0; i < 2; i++)
		m_data[i] = 0.0f;
}

// Returns the length of the vector
float Vector2::GetLength() const
{
	return sqrt(X * X + Y * Y);
}

// Normalizes the vector
void Vector2::Normalize()
{
	// Get length
	float length = GetLength();
	
	// Divide components by length
	for (int i = 0; i < 2; i++)
		m_data[i] /= length;
}

// Gets the distance between two vectors
float Vector2::GetDistance(const Vector2& otherVector)
{
	// The vector between the two points
	Vector2 difference;
	// Calculate components
	difference.X = X - otherVector.X;
	difference.Y = Y - otherVector.Y;

	// Return length of difference
	return difference.GetLength();
}

// Gets a pointer to the data of the vector
const float *Vector2::GetData() const
{
	return m_data;
}

// Vector2 index operator overload
float Vector2::operator[](unsigned int index)
{
	// Check for invalid index
	if (index > 1)
		throw "Error: Bad index used for Vector2 indexer.";
	else
		// Return component based on index
		return (index == 0 ? X : Y);
}

// Vector2 addition operator
const Vector2 Vector2::operator+(const Vector2& otherVector)
{
	// Result vector
	Vector2 result = *this;
	// Add components
	for (int i = 0; i < 2; i++)
		result.m_data[i] += otherVector.m_data[i];
		
	return result;
}

void Vector2::operator+=(const Vector2& otherVector)
{
	for (int i = 0; i < 2; i++)
		m_data[i] += otherVector.m_data[i];
}

// Vector2 subtraction operator
const Vector2 Vector2::operator-(const Vector2& otherVector)
{
	// Result vector
	Vector2 result = *this;
	// Subtract components
	for (int i = 0; i < 2; i++)
		result.m_data[i] -= otherVector.m_data[i];

	return result;
}

void Vector2::operator-=(const Vector2& otherVector)
{
	for (int i = 0; i < 2; i++)
		m_data[i] -= otherVector.m_data[i];
}

// Vector2 multiplication operator
const Vector2 Vector2::operator*(float value)
{
	// Result vector
	Vector2 result = *this;
	// Multiply components
	for (int i = 0; i < 2; i++)
		result.m_data[i] *= value;
		
	return result;
}

void Vector2::operator*=(float value)
{
	for (int i = 0; i < 2; i++)
		m_data[i] *= value;
}

// Vector2 division operator
const Vector2 Vector2::operator/(float value)
{
	// Result vector
	Vector2 result = *this;
	// Multiply components
	for (int i = 0; i < 2; i++)
		result.m_data[i] /= value;
		
	return result;
}

void Vector2::operator/=(float value)
{
	for (int i = 0; i < 2; i++)
		m_data[i] /= value;
}

// Vector3 default constructor
Vector3::Vector3()
	: X(m_data[0]), Y(m_data[1]), Z(m_data[2])
{
	// Set components
	for (int i = 0; i < 3; i++)
		m_data[i] = 0.0f;
}

// Vector3 constructor setting all components to the same value
Vector3::Vector3(float compValue)
	: X(m_data[0]), Y(m_data[1]), Z(m_data[2])
{
	// Set components
	for (int i = 0; i < 3; i++)
		m_data[i] = compValue;
}

// Vector3 constructor with parameters
Vector3::Vector3(float x, float y, float z)
	: X(m_data[0]), Y(m_data[1]), Z(m_data[2])
{
	X = x;
	Y = y;
	Z = z;
}

// Sets components
void Vector3::Set(float x, float y, float z)
{
	X = x;
	Y = y;
	Z = z;
}

// Copies components from another vector
void Vector3::Set(const Vector3& vector)
{
	for (int i = 0; i < 3; i++)
		m_data[i] = vector.m_data[i];
}

// Sets all vector components to zero
void Vector3::Zero()
{
	for (int i = 0; i < 3; i++)
		m_data[i] = 0.0f;
}

// Returns the length of the vector
float Vector3::GetLength() const
{
	return sqrt(X * X + Y * Y + Z * Z);
}

// Normalizes the vector
void Vector3::Normalize()
{
	// Get length
	float length = GetLength();
	
	// Divide components by length
	for (int i = 0; i < 3; i++)
		m_data[i] /= length;
}

// Gets the distance between two vectors
float Vector3::GetDistance(const Vector3& otherVector)
{
	// The vector between the two points
	Vector3 difference;
	// Calculate components
	difference.X = X - otherVector.X;
	difference.Y = Y - otherVector.Y;
	difference.Z = Z - otherVector.Z;

	// Return length of difference
	return difference.GetLength();
}

// Gets a pointer to the data of the vector
const float *Vector3::GetData() const
{
	return m_data;
}

// Vector3 index operator overload
float Vector3::operator[](unsigned int index)
{
	// Check for invalid index
	if (index > 2)
		throw "Error: Bad index used for Vector3 indexer.";
	else
		// Return component based on index
		return (index == 0 ? X : (index == 1 ? Y : Z));
}

// Vector3 addition operator
const Vector3 Vector3::operator+(const Vector3& otherVector)
{
	// Result vector
	Vector3 result = *this;
	// Add components
	for (int i = 0; i < 3; i++)
		result.m_data[i] += otherVector.m_data[i];
		
	return result;
}

void Vector3::operator+=(const Vector3& otherVector)
{
	for (int i = 0; i < 3; i++)
		m_data[i] += otherVector.m_data[i];
}

// Vector3 subtraction operator
const Vector3 Vector3::operator-(const Vector3& otherVector)
{
	// Result vector
	Vector3 result = *this;
	// Add components
	for (int i = 0; i < 3; i++)
		result.m_data[i] -= otherVector.m_data[i];
		
	return result;
}

void Vector3::operator-=(const Vector3& otherVector)
{
	for (int i = 0; i < 3; i++)
		m_data[i] -= otherVector.m_data[i];
}

// Vector3 multiplication operator
const Vector3 Vector3::operator*(float value)
{
	// Result vector
	Vector3 result = *this;
	// Multiply components
	for (int i = 0; i < 3; i++)
		result.m_data[i] *= value;
		
	return result;
}

void Vector3::operator*=(float value)
{
	for (int i = 0; i < 3; i++)
		m_data[i] *= value;
}

// Vector3 division operator
const Vector3 Vector3::operator/(float value)
{
	// Result vector
	Vector3 result = *this;
	// Multiply components
	for (int i = 0; i < 3; i++)
		result.m_data[i] /= value;
		
	return result;
}

void Vector3::operator/=(float value)
{
	for (int i = 0; i < 3; i++)
		m_data[i] /= value;
}
